package database

import (
	"context"
	"fmt"
	"log"
	"strconv"
	"time"

	"gitee.com/wangshh_123/cross-pay-go/src/config"

	"github.com/redis/go-redis/v9"
)

// RedisClient 是全局的 Redis 客户端实例
var RedisClient *redis.Client

// InitRedis 初始化 Redis 连接
func InitRedis() error {
	// 检查配置
	if config.GlobalConfig.Redis.Host == "" {
		return fmt.Errorf("redis host is empty")
	}
	if config.GlobalConfig.Redis.Port == "" {
		return fmt.Errorf("redis port is empty")
	}

	// 将端口字符串转换为整数
	port, err := strconv.Atoi(config.GlobalConfig.Redis.Port)
	if err != nil {
		return fmt.Errorf("invalid redis port: %v", err)
	}

	// 构建 Redis 地址
	addr := fmt.Sprintf("%s:%d", config.GlobalConfig.Redis.Host, port)
	log.Printf("Attempting to connect to Redis at %s", addr)

	// 打印 Redis 配置信息（隐藏密码）
	log.Printf("Redis config - Host: %s, Port: %d, DB: %d, PoolSize: %d, MinIdleConns: %d",
		config.GlobalConfig.Redis.Host,
		port,
		config.GlobalConfig.Redis.DB,
		config.GlobalConfig.Redis.PoolSize,
		config.GlobalConfig.Redis.MinIdleConns,
	)

	RedisClient = redis.NewClient(&redis.Options{
		Addr:            addr,
		Password:        config.GlobalConfig.Redis.Password,
		DB:              config.GlobalConfig.Redis.DB,
		PoolSize:        20,               // 增加连接池大小
		MinIdleConns:    5,                // 增加最小空闲连接数
		MaxRetries:      5,                // 增加重试次数
		DialTimeout:     10 * time.Second, // 增加连接超时时间
		ReadTimeout:     5 * time.Second,  // 增加读取超时时间
		WriteTimeout:    5 * time.Second,  // 增加写入超时时间
		PoolTimeout:     8 * time.Second,  // 增加池超时时间
		ConnMaxIdleTime: 10 * time.Minute, // 增加空闲连接最大生命周期
		ConnMaxLifetime: 30 * time.Minute, // 保持连接最大生命周期
	})

	// 测试连接
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	log.Printf("Testing Redis connection...")
	if err := RedisClient.Ping(ctx).Err(); err != nil {
		return fmt.Errorf("failed to connect to Redis at %s: %v", addr, err)
	}

	log.Printf("Successfully connected to Redis at %s", addr)
	return nil
}

// CloseRedis 关闭 Redis 连接
func CloseRedis() error {
	if RedisClient != nil {
		return RedisClient.Close()
	}
	return nil
}

// RedisKey 生成 Redis 键
func RedisKey(prefix string, keys ...string) string {
	if len(keys) == 0 {
		return prefix
	}
	return fmt.Sprintf("%s:%s", prefix, keys[0])
}

// SetWithExpiration 设置带过期时间的键值对
func SetWithExpiration(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	return RedisClient.Set(ctx, key, value, expiration).Err()
}

// Get 获取键值
func Get(ctx context.Context, key string) (string, error) {
	return RedisClient.Get(ctx, key).Result()
}

// GetInt64 获取整数类型的键值
func GetInt64(ctx context.Context, key string) (int64, error) {
	return RedisClient.Get(ctx, key).Int64()
}

// Delete 删除键
func Delete(ctx context.Context, key string) error {
	return RedisClient.Del(ctx, key).Err()
}

// Exists 检查键是否存在
func Exists(ctx context.Context, key string) (bool, error) {
	result, err := RedisClient.Exists(ctx, key).Result()
	return result > 0, err
}

// SetNX 设置键值对，仅当键不存在时
func SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) (bool, error) {
	return RedisClient.SetNX(ctx, key, value, expiration).Result()
}

// HSet 设置哈希表字段
func HSet(ctx context.Context, key string, values ...interface{}) error {
	return RedisClient.HSet(ctx, key, values...).Err()
}

// HGet 获取哈希表字段
func HGet(ctx context.Context, key, field string) (string, error) {
	return RedisClient.HGet(ctx, key, field).Result()
}

// HGetAll 获取哈希表所有字段
func HGetAll(ctx context.Context, key string) (map[string]string, error) {
	return RedisClient.HGetAll(ctx, key).Result()
}

// HDel 删除哈希表字段
func HDel(ctx context.Context, key string, fields ...string) error {
	return RedisClient.HDel(ctx, key, fields...).Err()
}

// Expire 设置键的过期时间
func Expire(ctx context.Context, key string, expiration time.Duration) error {
	return RedisClient.Expire(ctx, key, expiration).Err()
}

// TTL 获取键的剩余生存时间
func TTL(ctx context.Context, key string) (time.Duration, error) {
	return RedisClient.TTL(ctx, key).Result()
}

// Incr 将键的值增加1
func Incr(ctx context.Context, key string) (int64, error) {
	return RedisClient.Incr(ctx, key).Result()
}

// IncrBy 将键的值增加指定的整数
func IncrBy(ctx context.Context, key string, value int64) (int64, error) {
	return RedisClient.IncrBy(ctx, key, value).Result()
}

// Decr 将键的值减少1
func Decr(ctx context.Context, key string) (int64, error) {
	return RedisClient.Decr(ctx, key).Result()
}

// DecrBy 将键的值减少指定的整数
func DecrBy(ctx context.Context, key string, value int64) (int64, error) {
	return RedisClient.DecrBy(ctx, key, value).Result()
}

// LPush 将一个值插入到列表头部
func LPush(ctx context.Context, key string, values ...interface{}) error {
	return RedisClient.LPush(ctx, key, values...).Err()
}

// RPush 将一个值插入到列表尾部
func RPush(ctx context.Context, key string, values ...interface{}) error {
	return RedisClient.RPush(ctx, key, values...).Err()
}

// LPop 移除并返回列表的第一个元素
func LPop(ctx context.Context, key string) (string, error) {
	return RedisClient.LPop(ctx, key).Result()
}

// RPop 移除并返回列表的最后一个元素
func RPop(ctx context.Context, key string) (string, error) {
	return RedisClient.RPop(ctx, key).Result()
}

// LLen 获取列表长度
func LLen(ctx context.Context, key string) (int64, error) {
	return RedisClient.LLen(ctx, key).Result()
}

// SAdd 将一个成员元素加入到集合中
func SAdd(ctx context.Context, key string, members ...interface{}) error {
	return RedisClient.SAdd(ctx, key, members...).Err()
}

// SRem 移除集合中一个成员
func SRem(ctx context.Context, key string, members ...interface{}) error {
	return RedisClient.SRem(ctx, key, members...).Err()
}

// SIsMember 判断成员元素是否是集合的成员
func SIsMember(ctx context.Context, key string, member interface{}) (bool, error) {
	return RedisClient.SIsMember(ctx, key, member).Result()
}

// SMembers 返回集合中的所有成员
func SMembers(ctx context.Context, key string) ([]string, error) {
	return RedisClient.SMembers(ctx, key).Result()
}

// SCard 获取集合的成员数
func SCard(ctx context.Context, key string) (int64, error) {
	return RedisClient.SCard(ctx, key).Result()
}

// ZAdd 将一个成员元素及其分数值加入到有序集当中
func ZAdd(ctx context.Context, key string, score float64, member string) error {
	return RedisClient.ZAdd(ctx, key, redis.Z{Score: score, Member: member}).Err()
}

// ZRange 返回有序集中指定区间内的成员
func ZRange(ctx context.Context, key string, start, stop int64) ([]string, error) {
	return RedisClient.ZRange(ctx, key, start, stop).Result()
}

// ZCard 获取有序集合的成员数
func ZCard(ctx context.Context, key string) (int64, error) {
	return RedisClient.ZCard(ctx, key).Result()
}

// Pipeline 返回一个新的Pipeline
func Pipeline() redis.Pipeliner {
	return RedisClient.Pipeline()
}

// GetClient 返回Redis客户端实例
func GetClient() *redis.Client {
	return RedisClient
}
